package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.qo.QueryCourseModel;
import com.xuecheng.api.content.model.vo.CourseBaseVO;
import com.xuecheng.common.constant.ContentErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.enums.common.AuditEnum;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.enums.content.CourseGradeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.controller.CourseAuditController;
import com.xuecheng.content.convert.CourseBaseConvert;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.CourseMarket;
import com.xuecheng.content.entity.CoursePub;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.xuecheng.content.service.CourseMarketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestBody;

import java.beans.Transient;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {

    @Autowired
    private CourseMarketService courseMarketService;

    @Autowired
    private CourseBaseService courseBaseService;

    @Override
    public PageVO<CourseBase> queryCourseBaseList(PageRequestParams params, @RequestBody QueryCourseModel model, Long companyId) {

        //判单获取数据是否为空
        if (params.getPageNo() < 1) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }
        if (params.getPageSize() < 1) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }

        Page<CourseBase> basePage = new Page<>(params.getPageNo(), params.getPageSize());

        //查询数据
        LambdaQueryWrapper<CourseBase> wrapper = new LambdaQueryWrapper<>();
        String courseName = model.getCourseName();
        if (StringUtil.isNotBlank(courseName)) {
            wrapper.like(CourseBase::getName, courseName);
        }
        String auditSatus = model.getAuditSatus();
        if (StringUtil.isNotBlank(auditSatus)) {
            wrapper.eq(CourseBase::getAuditStatus, auditSatus);
        }

        //获取分页list集合
        Page<CourseBase> page = this.page(basePage, wrapper);

        //获取数据列表
        List<CourseBase> records = page.getRecords();
        //获取总页数
        long total = page.getTotal();


        List<CourseBaseDTO> dtos = Collections.emptyList();

        if (!(CollectionUtils.isEmpty(records))) {
            dtos = CourseBaseConvert.INSTANCE.entitys2dtos(records);
        }
        PageVO pageVO = new PageVO(dtos, total, params.getPageNo(), params.getPageSize());

        //封装构建并返回PageVo
        return pageVO;
    }


    /*
            业务分析：
            1.是否要开启事务
               如果是增删改操作，必须要开启事务
            2.判断关键数据
              有此数据才可以进行操作，一般有前端来传入
                来源：
                    数据库表约束
                    前端页面的表单说明
                        为必填项：红星
                    api接口文档（Yapi）
            3.判断业务数据（添加没有业务数据判断）
              系统中存在的数据，如果数据状态有问题，当前操作要终止，一般数据来源于后端
            4.判断数据是否要被赋值（默认值）
                status：数据库已经赋值，无需操作
                审核状态 auditStatus：新添加的课程默认审核状态--未提交（状态码）
            5.将dto转为po数据
                因为mp的api只能对po数据进行操作
            6.保存数据并返回结果，判断结果是否成功
            7.如果操作成功，将数据转为dto并返回
     */
    @Override
    @Transactional
    public CourseBaseDTO courseBasseDto(CourseBaseDTO dto) {


        //判断关键数据

        //3.判断业务数据（添加没有业务数据判断）
        //系统中存在的数据，如果数据状态有问题，当前操作要终止，一般数据来源于后端
        verifyCourseMsg(dto);


        //4.判断数据是否要被赋值（默认值）
        //status：数据库已经赋值，无需操作
        //审核状态 auditStatus：新添加的课程默认审核状态--未提交（状态码）
        dto.setAuditStatus(CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode());
        //5.将dto转为po数据
        CourseBase courseBase = CourseBaseConvert.INSTANCE.dtoentitypo(dto);

        //6.保存数据并返回结果，判断结果是否成功
        boolean rulice = this.save(courseBase);
        //判断是否保存成功
        if (!rulice) {
//            throw new RuntimeException("课程信息保存失败");
            ExceptionCast.cast(ContentErrorCode.E_120001);
        }
        //课程营销信息
        CourseMarket courseMarket = new CourseMarket();
        courseMarket.setCourseId(courseBase.getId());
        courseMarket.setCharge(dto.getCharge());
        courseMarket.setPrice(dto.getPrice().floatValue());

        //判断上是否收费
        String charge = dto.getCharge();
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(charge)) {
            BigDecimal price = dto.getPrice();
            if (ObjectUtils.isEmpty(price)) {
//                throw new RuntimeException("收费课程价格不能为空");
                ExceptionCast.cast(ContentErrorCode.E_120104);
            }
            courseMarket.setPrice(dto.getPrice().floatValue());
        }


        //判断课程营销数据是否保存成功
        boolean reliusMarket = courseMarketService.save(courseMarket);
        if (!reliusMarket) {
//            throw new RuntimeException("课程营销数据保存失败");
            ExceptionCast.cast(ContentErrorCode.E_120107);
        }

        // 7.如果操作成功，将数据转为dto并返回
        Long id = courseBase.getId();
        CourseBaseDTO courseBaseDTO = getnewrulist(dto, id);
        return courseBaseDTO;
    }

    private CourseBaseDTO getnewrulist(CourseBaseDTO dto, Long id) {

        CourseBase po = this.getById(id);
        CourseBaseDTO courseBaseDTO = CourseBaseConvert.INSTANCE.entity2dto(po);
        courseBaseDTO.setCharge(dto.getCharge());
        courseBaseDTO.setPrice(dto.getPrice());
        return courseBaseDTO;
    }

    private void verifyCourseMsg(CourseBaseDTO dto) {
        if (ObjectUtils.isEmpty(dto.getCompanyId())) {
//            throw new RuntimeException("公司ID不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120018);
        }

        if (StringUtil.isBlank(dto.getName())) {
            //throw new RuntimeException("课程名称不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120004);
        }
        if (StringUtil.isBlank(dto.getGrade())) {
//            throw new RuntimeException("课程等级不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120007);
        }
        if (StringUtil.isBlank(dto.getMt())) {
//            throw new RuntimeException("课程大分类不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120002);
        }
        if (StringUtil.isBlank(dto.getSt())) {
//            throw new RuntimeException("课程小分类不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120003);
        }
        if (StringUtil.isBlank(dto.getUsers())) {
//            throw new RuntimeException("适用人群不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120019);
        }
        if (StringUtil.isBlank(dto.getTeachmode())) {
//            throw new RuntimeException("课程教学模式不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120005);
        }
        if (StringUtil.isBlank(dto.getCharge())) {
//            throw new RuntimeException("课程收费不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120104);
        }
    }

    /*
     * 业务分析：
     *   1.判断关键数据
     *       courseBaseId  companyId
     *   2.判断业务数据
     *       课程基础信息
     *           判断是否存在
     *           判断是否是同一家教学机构
     *           判断是否删除
     *       课程营销
     *   3.查询数据并转为dto返回
     *
     * */
    @Override
    public CourseBaseDTO getCourseBase(Long courseBaseId, Long companyId) {

        //1.判断关键数据
        //        *       courseBaseId  companyId
        if (ObjectUtils.isEmpty(companyId) || ObjectUtils.isEmpty(companyId)) {
//            throw new RuntimeException("传入参数和接口不匹配");
            ExceptionCast.cast(ContentErrorCode.E_120020);
        }
        //2.判断业务数据
        //        *       课程基础信息
        //        *           判断是否存在
        //        *           判断是否是同一家教学机构
        //        *           判断是否删除
        //        *       课程营销

        CourseMarket makert = getCourseMarketByCourseId(courseBaseId);


        CourseBase base = getCourseBaseByBaseId(courseBaseId, companyId);

        //3.查询数据并转为dto返回
        CourseBaseDTO courseBaseDTO = CourseBaseConvert.INSTANCE.entity2dto(base);
        courseBaseDTO.setCharge(makert.getCharge());
        courseBaseDTO.setPrice(new BigDecimal(makert.getPrice().floatValue()));

        return courseBaseDTO;
    }


    private CourseBase getCourseBaseByBaseId(Long courseBaseId, Long companyId) {
        LambdaQueryWrapper<CourseBase> basewrapper = new LambdaQueryWrapper<>();

        basewrapper.eq(CourseBase::getId, courseBaseId);
        if (!(ObjectUtils.nullSafeEquals(companyId, CourseAuditController.OPERATION_FLAG))){
            basewrapper.eq(CourseBase::getCompanyId, companyId);
        }

        CourseBase base = this.getOne(basewrapper);
        if (ObjectUtils.isEmpty(base)) {
//            throw new RuntimeException("课程不存在");
            ExceptionCast.cast(ContentErrorCode.E_120022);
        }

        Integer status = base.getStatus();
        if (!(CommonEnum.USING_FLAG.getCodeInt().equals(status))) {
//            throw new RuntimeException("课程已经被删除");
            ExceptionCast.cast(ContentErrorCode.E_120021);
        }
        return base;
    }

    private CourseMarket getCourseMarketByCourseId(Long courseBaseId) {
        LambdaQueryWrapper<CourseMarket> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(CourseMarket::getCourseId, courseBaseId);

        CourseMarket makert = courseMarketService.getOne(lambdaQueryWrapper);

        if (ObjectUtils.isEmpty(makert)) {
//            throw new RuntimeException("课程营销数据不存在");
            ExceptionCast.cast(ContentErrorCode.E_120101);
        }
        return makert;
    }

    /*
     * 业务分析：
     *   1.判断关键数据
     *       可以使用添加的判断
     *       修改时：课程id是必须存在
     *   2.判断业务数据
     *       课程基础信息
     *           判断是否存在
     *           判断是否是同一家教学机构
     *           判断是否删除
     *           判断课程审核状态：未提交、审核未通过
     *       课程营销
     *   3.修改数据内容
     *       课程基础信息表
     *           有些内容是不容修改的：courseBaseId、companyid、auditstatus、status
     *       课程营销数据表
     *           charge price
     *        修改数据时要判断修改后结果
     *
     *   4.返回前端最新的数据库的数据并封装为dto返回
     *
     * */

    @Override
    @Transactional
    public CourseBaseDTO modifyCourseBase(CourseBaseDTO dto) {
        /*
         * 1.判断关键数据
         *       可以使用添加的判断
         *       修改时：课程id是必须存在
         * */
        verifyCourseMsg(dto);
        Long courseBaseId = dto.getCourseBaseId();
        if (ObjectUtils.isEmpty(courseBaseId)) {
//            throw new RuntimeException("课程id不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120009);
        }
        //2.判断业务数据
        //        *       课程基础信息
        //        *           判断是否存在
        //        *           判断是否是同一家教学机构
        //        *           判断是否删除
        //        *           判断课程审核状态：未提交、审核未通过
        Long companyId = dto.getCompanyId();
        getCourseBaseByBaseId(courseBaseId, companyId);
        String auditStatus = dto.getAuditStatus();
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)
        ) {
            //throw new RuntimeException("课程审核状态异常");

            ExceptionCast.cast(ContentErrorCode.E_120201);
        }
        //        *       课程营销
        CourseMarket courseMarketByCourseId = getCourseMarketByCourseId(courseBaseId);

        //3.修改数据内容
        //        *       课程基础信息表
        //        *           有些内容是不容修改的：courseBaseId、companyid、auditstatus、status
        //        *       课程营销数据表
        //        *           charge price
        //        *        修改数据时要判断修改后结果

        CourseBase po = CourseBaseConvert.INSTANCE.dtoentitypo(dto);

        //设置不能修该的选项
        po.setCompanyId(null);
        po.setAuditStatus(null);
        po.setStatus(null);

        boolean baserulit = this.updateById(po);

        if (!baserulit) {
//            throw new RuntimeException("课程信息修改失败");
            ExceptionCast.cast(ContentErrorCode.E_120008);
        }

        LambdaUpdateWrapper<CourseMarket> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseMarket::getCharge, dto.getCharge());

        String charge = dto.getCharge();
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(charge)) {

            BigDecimal price = dto.getPrice();
            if (ObjectUtils.isEmpty(price)) {
//                throw new RuntimeException("价格不能为空");
                ExceptionCast.cast(ContentErrorCode.E_120104);
            }

            updateWrapper.set(CourseMarket::getPrice, price);

            boolean update = courseMarketService.update(updateWrapper);

            if (!update) {
//                throw new RuntimeException("修改课程的营销数据失败");
                ExceptionCast.cast(ContentErrorCode.E_120107);
            }

        }

        //4.返回前端最新的数据库的数据并封装为dto返回
        CourseBaseDTO getnewrulist = getnewrulist(dto, courseBaseId);

        return getnewrulist;
    }


    //业务需求：
    //1.判断关键数据的合法性
    //2.根据id活得课程基本信息并进行判断
    //3.修改课程信息状态值


    @Override
    @Transactional
    public void removeCoursebase(Long courseBaseId, Long companyId) {

        //1.判断关键数据的合法性
        if (ObjectUtils.isEmpty(courseBaseId) ||
                ObjectUtils.isEmpty(companyId)) {
//            throw new RuntimeException("传入参数和接口不匹配");
            ExceptionCast.cast(ContentErrorCode.E_120020);
        }

        //根据id获得得课程的基本信息并判断
        CourseBase courseBase = getById(courseBaseId);
        if (ObjectUtils.isEmpty(courseBase)) {
//            throw new RuntimeException("课程不存在");
            ExceptionCast.cast(ContentErrorCode.E_120010);
        }

        if (!ObjectUtils.nullSafeEquals(companyId, courseBase.getCompanyId())) {
//            throw new RuntimeException("课程不是一家机构的");
            ExceptionCast.cast(ContentErrorCode.E_120406);
        }

        Integer status = courseBase.getStatus();
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(status) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(status) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(status)
        ) {
//            throw new RuntimeException("课程的审核状态");
            ExceptionCast.cast(ContentErrorCode.E_120014);
        }

        //3.修改课程的基本信息
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getStatus, CommonEnum.DELETE_FLAG.getCodeInt());
        updateWrapper.set(CourseBase::getCreateDate, LocalDateTime.now());

        updateWrapper.eq(CourseBase::getId, courseBaseId);

        boolean update = update(updateWrapper);

        if (!update) {
//            throw new RuntimeException("删除失败");
            ExceptionCast.cast(ContentErrorCode.E_120023);
        }


    }

    /*
     * 业务分析：
     *   1.判断关键数据
     *   2.判断业务数据
     *       课程基础信息
     *           判断是否存在
     *           判断是否是同一家教学机构
     *           判断是否删除
     *           判断审核状态
     *   3.修改课程审核状态
     *       已提交
     * */
    @Transactional
    public void commitCourseBase(Long courseBaseId, Long compantId) {

        // 1.判断关键数据

        if (ObjectUtils.isEmpty(compantId) ||
                ObjectUtils.isEmpty(courseBaseId)
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120020);
        }
        //     *   2.判断业务数据
        //     *       课程基础信息
        //     *           判断是否存在
        //     *           判断是否是同一家教学机构
        //     *           判断是否删除
        //     *           判断审核状态

        //根据id获得得课程的基本信息并判断
        CourseBase courseBase = getById(courseBaseId);
        if (ObjectUtils.isEmpty(courseBase)) {
//            throw new RuntimeException("课程不存在");
            ExceptionCast.cast(ContentErrorCode.E_120010);
        }

        if (!ObjectUtils.nullSafeEquals(compantId, courseBase.getCompanyId())) {
//            throw new RuntimeException("课程不是一家机构的");
            ExceptionCast.cast(ContentErrorCode.E_120406);
        }

        Integer status = courseBase.getStatus();
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(status) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(status) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(status)
        ) {
//            throw new RuntimeException("课程的审核状态");
            ExceptionCast.cast(ContentErrorCode.E_120014);
        }


        //3.修改课程审核状态
        //     已提交
        //  createDate  changeDate 使用MP自动填充来完成
        //  UpdateWrapper 会将MP的自动填充功能失效
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getAuditStatus, CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode());
        updateWrapper.set(CourseBase::getAuditDate, LocalDateTime.now());
        updateWrapper.eq(CourseBase::getId, courseBaseId);

        boolean update = this.update(updateWrapper);
        if (!update) {
            ExceptionCast.cast(ContentErrorCode.E_120024);
        }


    }

    /*
     * 业务分析：
     *   1.判断关键数据
     *       auditMind  auditStatus  courseid
     *   2.判断业务数据
     *       课程基础信息
     *           判断是否存在
     *           判断是否删除
     *           判断审核状态
     *               必须为：已提交
     *       审核状态
     *           运营平台只能给课程审核状态赋值：审核通过、审核未通过
     *   3.修改课程审核信息
     *       auditMind  auditStatus  auditNum（每次+1）
     * */
    public void approveCourse(CourseBaseDTO courseBaseDTO) {

        // 1.判断关键数据
        //     auditMind  auditStatus  courseid
        if (StringUtil.isBlank(courseBaseDTO.getAuditMind()) ||
                StringUtil.isBlank(courseBaseDTO.getAuditStatus()) ||
                ObjectUtils.isEmpty(courseBaseDTO.getCourseBaseId())
        ){
            ExceptionCast.cast(ContentErrorCode.E_120025);
        }

        //2.判断业务数据
        //    课程基础信息
        //        判断是否存在
        //        判断是否删除
        //        判断审核状态
        //            必须为：已提交
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseBase::getId,courseBaseDTO.getCourseBaseId());
        queryWrapper.eq(CourseBase::getStatus, CommonEnum.USING_FLAG.getCodeInt());
        queryWrapper.eq(CourseBase::getAuditStatus,CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode());

        int count = this.count(queryWrapper);
        if (count < 1) {
            ExceptionCast.cast(ContentErrorCode.E_120205);
        }

        //审核状态
        //    运营平台只能给课程审核状态赋值：审核通过、审核未通过
        String auditStatus = courseBaseDTO.getAuditStatus();
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)
        ){
            ExceptionCast.cast(ContentErrorCode.E_120206);
        }


        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getAuditMind,courseBaseDTO.getAuditMind());
        updateWrapper.set(CourseBase::getAuditStatus,courseBaseDTO.getAuditStatus());
        updateWrapper.set(CourseBase::getCreateDate,LocalDateTime.now());
        boolean update = this.update(updateWrapper);
        if (!update) {
            ExceptionCast.cast(ContentErrorCode.E_120024);
        }


    }

}
